<?php
// +----------------------------------------------------------------------
// | View 视图服务
// +----------------------------------------------------------------------
// | * 视图层
// | * 1.查询所有关联表的字段
// | * 2.处理字段（可显示、可编辑、可排序、可分组、可过滤）、还要通过临时字段、字段权限进行判断，组装出view需要的字段
// | * 3.组装view视图的表格列
// +----------------------------------------------------------------------
// | 错误编码头 231xxx
// +----------------------------------------------------------------------

namespace common\service;

use common\model\EntityModel;
use common\model\ProjectMemberModel;
use common\model\ProjectModel;
use common\model\UserModel;
use support\EntityTaskFilterParser;
use support\ErrorCode;
use support\SingletonTrait;
use Webman\Stomp\Client;

class ReportPushService
{
    use SingletonTrait;
    use EntityTaskFilterParser;


    /**
     * 推送到不同的角色项目成员
     * @param $time
     * @param $role
     * @param $projectId
     * @return string[]
     */
    public function pushProjectRoleUserList($time, $role, $projectId, $stepCategoryRemark = [])
    {
        // 查出项目接收每日报表的项目
        $projectData = model(ProjectModel::class)
            ->where([
                'id' => $projectId
            ])
            ->field('id,name,tenant_id')
            ->find();
        if (empty($projectData)) {
            throw_strack_exception('project not found', ErrorCode::PROJECT_NOT_FOUND);
        }
        if ($time > time()) {
            throw_strack_exception('push time must be earlier than or equal to the current time', ErrorCode::TIME_MUST_LESS_THAN_CURRENT_TIME);
        }

        $nowDayTimeData = get_current_day_range($time);

        $data['role'] = $role;
        $data['project_id'] = $projectData['id'];
        $data['start_time'] = $nowDayTimeData['sdate'];
        $data['end_time'] = $nowDayTimeData['edate'];
        $data['everyday_report_time'] = $nowDayTimeData['sdate']; // 日报查询时间

        $stepCategoryRemarkMap = [];
        foreach ($stepCategoryRemark as $stepCategoryRemarkItem) {
            foreach (explode(",", $stepCategoryRemarkItem['step_category_ids']) as $stepCategoryId) {
                $stepCategoryRemarkMap[$stepCategoryId] = $stepCategoryRemarkItem['remark'];
            }
        }
        $data['step_category_remark'] = $stepCategoryRemarkMap; //环节备注
        Client::send('send_every_day_report', build_queue_data_with_xu($data));
        return ['version' => '3', 'data' => $data];
    }

    /**
     * 通过每日定时推送配置推送报表
     * @return array
     */
    public function pushEveryDayReportMsg()
    {
        // 查询每个项目的每日推送时间
        $projectList = model(ProjectModel::class)
            ->where([
                "JSON_UNQUOTE(JSON_EXTRACT(json, '$.every_report_push_config.is_open_everyday_push'))" => 'yes',
                "JSON_UNQUOTE(JSON_EXTRACT(json, '$.every_report_push_config.everyday_push_hour'))" => ['NEQ', '']
            ])
            ->field([
                'id',
                'name',
                'tenant_id',
                "JSON_UNQUOTE(JSON_EXTRACT(json, '$.every_report_push_config.is_open_everyday_push')) as is_open_everyday_push",
                "JSON_UNQUOTE(JSON_EXTRACT(json, '$.every_report_push_config.everyday_push_hour')) as everyday_push_hour",
                "JSON_UNQUOTE(JSON_EXTRACT(json, '$.every_report_push_config.push_role')) as push_role"
            ])
            ->select();
        if (empty($projectList)) {
            throw_strack_exception('push everyday report config is null', 0);
        }

        $projectList = array_map(function ($tmp) {
            $tmp['push_role'] = json_decode($tmp['push_role'], true);
            return $tmp;
        }, $projectList);

        // 伪造请求用户
        $adminData = model(UserModel::class)->where(['id' => 210])->find();
        $adminData['is_system'] = 'no';
        $adminData['active'] = true;
        $adminData['id'] = $adminData['union_id'];
        $adminData['channel'] = '';

        // 当天开始时间
        $startTime = strtotime(date('Y-m-d'), time());
        $endTime = strtotime(date('Y-m-d 23:59:59'), time());
        foreach ($projectList as $projectItem) {

            $everydayPushHour = strtotime(date('Y-m-d ' . $projectItem['everyday_push_hour'] . ':00', time()));
            $delayTime = $everydayPushHour - time();
            if ($delayTime <= 0) {
                $delayTime = 0; // 正好是时间点,则立即推送
            }

            $data['is_every_push'] = 'yes'; // 每日推送标识
            $data['everyday_push_hour'] = $projectItem['everyday_push_hour'];
            $data['role'] = $projectItem['push_role'];
            $data['project_id'] = $projectItem['id'];
            $data['start_time'] = $startTime;
            $data['end_time'] = $endTime;
            $data['everyday_report_time'] = $startTime; // 日报查询时间
            $adminData['tenant_id'] = $projectItem['tenant_id'];
            $data['xu'] = base64_encode(json_encode($adminData));
            Client::send('send_every_day_report', build_queue_data_with_xu($data), $delayTime);
        }
        return $projectList;
    }

    /**
     * 推送指定角色成员
     * @param $projectId
     * @param $startTime
     * @param $endTime
     * @param $everydayReportTime
     * @param $role
     * @return void
     * @throws \think\Exception
     */
    public function pushSpecifyRoleProjectMember($projectId, $startTime, $endTime, $everydayReportTime, $role, $stepCategoryRemark = [])
    {
        // 查询项目下的成员
        $projectMemberUserList = model(ProjectMemberModel::class)
            ->join('user on user.id = project_member.user_id')
            ->where(['project_member.project_id' => $projectId])->field('distinct user.union_id')->select();
        if (empty($projectMemberUserList)) {
            throw_strack_exception(' project member null', 0);
        }
        $needRoleUserList = teamones_request('teamones-im', 'department/select_user_list', [
            'param' => [
                'filter' => [
                    'role.code' => ['-in', join(',', $role)],
                    'user.id' => ['-in', join(',', array_column($projectMemberUserList, 'union_id'))]
                ]
            ]
        ]);
        if (empty($needRoleUserList['data'])) {
            throw_strack_exception(' project member is empty,push fail', 0);
        }
        $this->pushEverydayReport([
            'project_id' => $projectId,
            'receiverUnionIds' => array_column($needRoleUserList['data'], 'id'),
            'start_time' => $startTime,
            'end_time' => $endTime,
            'everyday_report_time' => $everydayReportTime,
            'step_category_remark' => $stepCategoryRemark
        ]);
    }

    /**
     * 推送每日统计
     * @param $data
     * @return string[]
     * @throws \think\Exception
     */
    public function pushEverydayReport($data)
    {
        // 所有大环节
        $showStepCategoryGroup = ProjectService::getInstance()->getShowStepCategoryGroup();
        if (empty($showStepCategoryGroup)) {
            throw_strack_exception('show_step_category null', 0);
        }
        // 追加导演
        $showStepCategoryGroup = array_merge([
            [
                'id' => '导演', 'name' => '导演', 'children' => [], 'children_ids' => [5], 'link_module_code' => 'role',
                'department_id' => 208, 'start_time' => $data['end_time'], 'end_time' => $data['end_time']
            ]
        ], $showStepCategoryGroup);

        // 封板集
        $getStepCategorySealEpisodeList = $this->getStepCategorySealEpisodeList([
            'project_id' => $data['project_id'],
            'start_time' => $data['start_time'],
            'end_time' => $data['end_time'],
            'step_category_id_list' => []
        ]);

        $episodeList = [];
        foreach ($getStepCategorySealEpisodeList ?? [] as $getStepCategorySealEpisodeItem) {
            $episodeList[] = $getStepCategorySealEpisodeItem['code'];
        }

        // 组织推送数据
        $pushData[] = [
            'title' => '封板',
            'final_rate' => 0,
            'abnormal' => 0,
            'unresolved' => 0,
            'episode_list' => $episodeList,
            'children_ids' => [],
            'link_module_code' => 'episode',
            'department_id' => 0,
            'start_time' => $data['start_time'],
            'end_time' => $data['end_time'],
            'project_id' => intval($data['project_id'])
        ];

        $projectData = model(ProjectModel::class)->where(['id' => $data['project_id']])->field('id,tenant_id,name')->find();


        $stepCategoryRemark = $data['step_category_remark'] ?? [];
        foreach ($showStepCategoryGroup as $showStepCategoryGroupItem) {
            $requestData = [
                'project_id' => intval($data['project_id']),
                'start_time' => intval($data['start_time']),
                'end_time' => intval($data['end_time']),
                'todo_step_category_id_list' => $showStepCategoryGroupItem['children_ids']
            ];
            if (!empty($showStepCategoryGroupItem['department_id'])) {
                $requestData['department_id'] = $showStepCategoryGroupItem['department_id'];
                unset($requestData['todo_step_category_id_list']);
            }
            // 本环节应完成
            $taskDoneStatisticsData = $this->taskDoneStatistics($requestData);
            $taskDoneStatisticsData = $taskDoneStatisticsData['data'] ?? [];
            // 本环节应交付
            $taskDeliveryStatisticsData = $this->taskDeliveryStatistics($requestData);
            $taskDeliveryStatisticsData = $taskDeliveryStatisticsData['data'] ?? [];
            // 新增异常
            $getGroupAbnormalAddCountData = $this->getGroupAbnormalAddCount($requestData);
            $getGroupAbnormalAddCountData = $getGroupAbnormalAddCountData['data'] ?? 0;
            // 延期异常
            $getGroupAbnormalDelayTaskCountData = $this->getGroupAbnormalDelayTaskCount($requestData);
            $getGroupAbnormalDelayTaskCountData = $getGroupAbnormalDelayTaskCountData['data'] ?? 0;
            // 完成率计算
            $finalRate = '0.00';
            if (!empty($taskDoneStatisticsData['in_plan_done']) && !empty($taskDoneStatisticsData['plan_done'])) {
                $finalRate = $taskDoneStatisticsData['in_plan_done'] / $taskDoneStatisticsData['plan_done'];
            }
            // 交付率计算
            $deliveryRate = '0.00';
            if (!empty($taskDeliveryStatisticsData['in_plan_delivery']) && !empty($taskDeliveryStatisticsData['plan_delivery'])) {
                $deliveryRate = $taskDeliveryStatisticsData['in_plan_delivery'] / $taskDeliveryStatisticsData['plan_delivery'];
            }
            // 未解决
//            $requestData['tenant_id'] = $projectData['tenant_id'];
//            $unresolved = $this->getUnresolved($requestData);

            $currentRemark = '';
            if ($showStepCategoryGroupItem['name'] == '导演') {
                $currentRemark = $stepCategoryRemark[$showStepCategoryGroupItem['name']] ?? '';
            } else {
                foreach ($showStepCategoryGroupItem['children_ids'] as $childrenId) {
                    if (empty($currentRemark) && isset($stepCategoryRemark[$childrenId])) {
                        $currentRemark = $stepCategoryRemark[$childrenId];
                    }
                }
            }


            // 未处理
            $requestData['tenant_id'] = $projectData['tenant_id'];
            $unprocessed = $this->getUnprocessed($requestData);
            $unprocessed = $unprocessed['data']['in_wait'] ?? 0;
            $pushData[] = [
                'title' => $showStepCategoryGroupItem['name'],
                'final_rate' => sprintf("%.2f", $finalRate), // [完成率]=单环节当日"已完成"的任务数/单环节当日计划完成任务总数
                'delivery_rate' => sprintf("%.2f", $deliveryRate), // [完成率]=单环节当日"已完成"的任务数/单环节当日计划完成任务总数
                'abnormal' => $getGroupAbnormalAddCountData + $getGroupAbnormalDelayTaskCountData, // [异常]=新增任务+延期任务
                'unresolved' => [], // 未解决
                'unprocessed' => $unprocessed, // 未处理
                'episode_list' => [],
                'children_ids' => $showStepCategoryGroupItem['children_ids'],
                'link_module_code' => $showStepCategoryGroupItem['link_module_code'],
                'department_id' => $showStepCategoryGroupItem['department_id'] ?? 0,
                'start_time' => intval($data['start_time']),
                'end_time' => intval($data['end_time']),
                'project_id' => intval($data['project_id']),
                'remark' => $currentRemark
            ];
        }

        $this->pushEveryDayMsg($pushData, $projectData, $data['everyday_report_time'], $data['receiverUnionIds']);
        return ['msg' => '日报发送成功'];
    }


    /**
     * 发送日报消息
     * @param $msgData
     * @param $projectData
     * @param $everydayReportTime
     * @param $receiverUnionIds
     * @return array|void
     * @throws \think\Exception
     */
    function pushEveryDayMsg($msgData, $projectData, $everydayReportTime, $receiverUnionIds = [])
    {
        if (empty($msgData) || empty($projectData) || empty($receiverUnionIds)) {
            return [];
        }
        $templateId = OptionsService::getInstance()->getOptionsConfigItemData('message_notify_template_config', 'notify_task_member_template_id');
        $messageParam = [
            'title' => $projectData['name'] . date('Y年m月d日', $everydayReportTime) . '报表',
            'send_at' => date('Y-m-d H:i:s', time()), // 日报发送时间
            'everyday_report_time' => $everydayReportTime, // 日报查询时间
            'content' => $msgData,
            'project_name' => $projectData['name'],
            'project_id' => $projectData['id'],
        ];
        $msg = [
            "param" => $messageParam,
            'template_id' => $templateId,
            'content_type' => 'card_message',
            'notice_type' => 'message_producer',
            'is_popup' => 1,
            'message_key' => 'notify_everyday_report'
        ];
        foreach (array_unique($receiverUnionIds) as $user) {
            $msg['receiver'] = $user;
            Client::send("send_notify_message_v2", build_queue_data_with_xu($msg));
        }

        // 更新最新推送时间
        $updateDate = [
            'id' => $projectData['id'],
            'last_every_report_push_time' => time()
        ];
        $projectCommonService = CommonService::instance('project');
        $projectCommonService->update($updateDate, 'project', true);

    }


    /**
     * 未解决：
     * 未完成+未交付+待处理工单
     * 备注：如果同一个任务今日需要完成和交付，但是都没有完，统计一次（未交付大于未完成，只统计未交付）
     * @return array
     */
    public function getUnresolved($requestData)
    {
        // 获取待处理工单
        $getGroupAbnormalWorkOrderCount = $this->getGroupAbnormalWorkOrderCount($requestData);

        $todoStepCategoryId = null;
        if (!empty($requestData['todo_step_category_id_list'])) {
            $todoStepCategoryId = ['IN', $requestData['todo_step_category_id_list']];
        }

        // 交付任务未完成
        $queryDeliveryFilter = $this->parseMultipleEntityTaskFilter([
            'task.project_id' => $requestData['project_id'],
            'time_search' => [$requestData['start_time'], $requestData['end_time']],
            'only_not_done' => 'yes',
            'task.step_type' => ['IN', 'step,standard_make_to_do'],
            'time_search_type' => 'delivery',
            'task.tenant_id' => $requestData['tenant_id'],
            'todo_step_category_id' => $todoStepCategoryId,
            'department_id_user_filter' => $requestData['department_id'] ?? null
        ]);

        $stepDeliveryDoneData = ProducerManageService::getInstance()->getTaskListQuery($this->tableList)->where($queryDeliveryFilter)
            ->field('distinct task.id as task_id')
            ->select();

        // 标准任务未完成
        $standardUnDoneFilter = $this->parseMultipleEntityTaskFilter([
            'standard_or_other' => 'yes',
            'task.project_id' => $requestData['project_id'],
            'task.step_type' => ['IN', 'standard_meeting,standard_review'],
            'task.plan_end_time' => ['BETWEEN', [$requestData['start_time'], $requestData['end_time']]],
            'only_not_done' => 'yes',
            'todo_step_category_id' => $todoStepCategoryId,
            'task.tenant_id' => $requestData['tenant_id'],
            'department_id_user_filter' => $requestData['department_id'] ?? null
        ]);
        $standardUnDoneData = ProducerManageService::getInstance()->getTaskListQuery($this->tableList)
            ->where($standardUnDoneFilter)
            ->field("distinct task.id as task_id")
            ->select();

        // 本环节生产任务未完成
        $productTaskNotFinalWhere = $this->parseMultipleEntityTaskFilter([
            'task.project_id' => $requestData['project_id'],
            'time_search' => [$requestData['start_time'], $requestData['end_time']],
            'only_not_done' => 'yes',
            'task.step_type' => ['IN', 'step,standard_make_to_do'],
            'todo_step_category_id' => $todoStepCategoryId,
            'task.tenant_id' => $requestData['tenant_id'],
            'department_id_user_filter' => $requestData['department_id'] ?? null
        ]);

        $productTaskNotFinalData = ProducerManageService::getInstance()->getTaskListQuery($this->tableList)->where($productTaskNotFinalWhere)->field('distinct task.id as task_id')->select();

        return [
            'product_task_un_final_data' => $productTaskNotFinalData ?? [], // 本环节-生产任务未完成
            'standard_un_done' => $standardUnDoneData ?? [], // 本环节-标准任务未完成
            'delivery_un_done' => $stepDeliveryDoneData ?? [], // 本环节-应交付未完成
            'group_abnormal_work_order_count' => $getGroupAbnormalWorkOrderCount['data'] ?? 0 // 待处理工单
        ];
    }

    /**
     * 未处理
     * @param $requestData
     * @return int[]
     */
    public function getUnprocessed($requestData)
    {
        return teamones_request('teamones-olap-sr', 'workbench/today_abnormal_task_count', $requestData);
    }


    /**
     * 环节应交付
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function getGroupDeliveryCount($requestData)
    {
        return teamones_request('teamones-olap-sr', 'workbench/group_delivery_count', $requestData);
    }

    /**
     * 环节应完成
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function getGroupPlanDoneCount($requestData)
    {
        /**
         * task_plan_done_step 生产任务已完成
         * task_plan_total_step 生产任务计划完成
         *
         * task_plan_total_standard_todo 标准任务计划完成
         * task_plan_done_standard_todo 标准任务已完成
         *
         * task_plan_done 计划已完成总数
         * task_plan_total 计划完成总数
         */
        return teamones_request('teamones-olap-sr', 'workbench/group_plan_done_count', $requestData);
    }

    /**
     * 获取环节新增异常任务
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function getGroupAbnormalAddCount($requestData)
    {
        return teamones_request('teamones-olap-sr', 'workbench/group_abnormal_add_count', $requestData);
    }

    /**
     * 获取延期异常任务
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function getGroupAbnormalDelayTaskCount($requestData)
    {
        return teamones_request('teamones-olap-sr', 'workbench/group_abnormal_delay_task_count', $requestData);
    }

    /**
     * 获取已封板的集数
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function getStepCategorySealEpisodeList($requestData)
    {
        $where = [
            'project_id' => $requestData['project_id'],
            "JSON_UNQUOTE(JSON_EXTRACT(json,'$.episode_seal_time'))" => ['BETWEEN', [$requestData['start_time'], $requestData['end_time']]],
            'module_id' => module_by_code('episode')['id']
        ];
        $episodeList = model(EntityModel::class)->where($where)->field('id,name,code')->select();
        if (empty($episodeList)) {
            return [];
        }
        return $episodeList;
    }

    /**
     * 获取待处理工单
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function getGroupAbnormalWorkOrderCount($requestData)
    {
        return teamones_request('teamones-olap-sr', 'workbench/group_abnormal_work_order_count', $requestData);
    }

    /**
     * 应完成
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function taskDoneStatistics($requestData)
    {
        /**
         * plan_done 计划已完成总数
         * in_plan_done 计划完成总数
         */
        return teamones_request('teamones-olap-sr', 'task_statistics/task_done_statistics', $requestData);
    }


    /**
     * 应交付
     * @param $requestData
     * @return array|mixed|\Yurun\Util\YurunHttp\Http\Response
     */
    public function taskDeliveryStatistics($requestData)
    {
        /**
         * plan_delivery 计划已交付总数
         * in_plan_delivery 计划交付总数
         */
        return teamones_request('teamones-olap-sr', 'task_statistics/task_delivery_statistics', $requestData);
    }
}


